/*
 * GraphQL年龄过滤器 - 人员年龄GraphQL过滤器
 * 
 * 主要功能：
 * - 实现基于年龄的GraphQL过滤逻辑
 * - 支持多种关系运算符的年龄过滤
 * - 提供离线过滤和单独请求处理
 * - 演示复杂过滤逻辑的实现
 */

using GraphQL;
using Lombiq.TrainingDemo.Models;
using OrchardCore.ContentManagement;
using OrchardCore.ContentManagement.GraphQL.Queries;
using OrchardCore.DisplayManagement.Shapes;
using OrchardCore.Modules;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using YesSql;
using static Lombiq.TrainingDemo.GraphQL.Services.ContentItemTypeBuilder;

namespace Lombiq.TrainingDemo.GraphQL.Services;

/// <summary>
/// 人员年龄GraphQL过滤器 - 实现基于年龄的GraphQL过滤逻辑
/// 
/// 主要用途：
/// - 实现基于年龄的GraphQL过滤逻辑
 //* - 支持多种关系运算符的年龄过滤
 //* - 提供离线过滤和单独请求处理
 //* - 演示复杂过滤逻辑的实现
 //* 
 //* 使用场景：
/// - 在GraphQL查询中按年龄过滤人员
/// - 支持年龄的比较运算（大于、小于、等于等）
/// - 处理无法通过YesSql查询表达的复杂逻辑
/// - 提供灵活的年龄过滤功能
/// 
/// 设计原因：
/// - 为GraphQL查询提供年龄过滤功能
/// - 支持复杂的业务逻辑过滤
/// - 实现无法通过索引表达的过滤条件
/// - 提供灵活的过滤机制
/// 
/// 设计模式：
/// - 过滤器模式：实现IGraphQLFilter<T>接口
/// - 后处理模式：使用PostQueryAsync进行离线过滤
/// - 参数解析模式：从GraphQL参数中提取过滤条件
/// - 关系运算模式：支持多种比较运算符
/// </summary>
// IGraphQLFilters可以向YesSql查询添加条件，更改其结果，或两者都做。
public class PersonAgeGraphQLFilter : IGraphQLFilter<ContentItem>
{
    private readonly IClock _clock;

    /// <summary>
    /// 构造函数 - 注入时钟服务
    /// </summary>
    /// <param name="clock">时钟服务，用于获取当前时间</param>
    public PersonAgeGraphQLFilter(IClock clock) => _clock = clock;

    /// <summary>
    /// 预查询方法 - 在查询执行前处理
    /// 
    /// 功能说明：
    /// - 可以修改YesSql查询
    /// - 当前实现直接返回原查询
    /// - 建议使用IIndexAliasProvider方法处理复杂查询
    /// </summary>
    /// <param name="query">原始查询</param>
    /// <param name="context">字段解析上下文</param>
    /// <returns>处理后的查询</returns>
    public Task<IQuery<ContentItem>> PreQueryAsync(IQuery<ContentItem> query, IResolveFieldContext context) =>
        Task.FromResult(query);

    /// <summary>
    /// 后查询方法 - 在查询执行后进行过滤
    /// 
    /// 功能说明：
    /// - 处理无法通过YesSql查询表达的复杂逻辑
    /// - 从GraphQL参数中提取年龄过滤条件
    /// - 计算人员年龄并进行过滤
    /// - 支持多种关系运算符
    /// 
    /// 过滤逻辑：
    /// - 提取年龄相关的GraphQL参数
    /// - 计算人员的实际年龄
    /// - 根据关系运算符进行过滤
    /// - 返回过滤后的内容项
    /// </summary>
    /// <param name="contentItems">内容项集合</param>
    /// <param name="context">字段解析上下文</param>
    /// <returns>过滤后的内容项集合</returns>
    public Task<IEnumerable<ContentItem>> PostQueryAsync(
        IEnumerable<ContentItem> contentItems,
        IResolveFieldContext context)
    {
        var (name, value) = context.Arguments.FirstOrDefault(
            argument => argument.Value.Value is int && argument.Key.StartsWithOrdinal(AgeFilterName));

        if (name != null && value.Value is int age)
        {
            var now = _clock.UtcNow;
            if (name == "age") name = "age_eq";
            var filterType = name[^2..]; // 名称运算符如gt、le等

            contentItems = contentItems.Where(item =>
                item.As<PersonPart>()?.BirthDateUtc is { } birthDateUtc &&
                Filter((now - birthDateUtc).TotalYears(), age, filterType));
        }

        return Task.FromResult(contentItems);
    }

    /// <summary>
    /// 过滤方法 - 根据关系运算符进行年龄比较
    /// 
    /// 功能说明：
    /// - 支持多种关系运算符的比较
    /// - 包括大于、小于、等于、不等于等
    /// - 提供类型安全的年龄比较
    /// 
    /// 支持的运算符：
    /// - ge：大于等于
    /// - gt：大于
    /// - le：小于等于
    /// - lt：小于
    /// - ne：不等于
    /// - 默认：等于
    /// </summary>
    /// <param name="totalYears">实际年龄</param>
    /// <param name="age">过滤条件年龄</param>
    /// <param name="filterType">过滤类型</param>
    /// <returns>是否满足过滤条件</returns>
    private static bool Filter(int totalYears, int age, string filterType) =>
        filterType switch
        {
            "ge" => totalYears >= age,
            "gt" => totalYears > age,
            "le" => totalYears <= age,
            "lt" => totalYears < age,
            "ne" => totalYears != age,
            _ => totalYears == age,
        };
}

// 训练部分结束：GraphQL

// 下一站：Activities/ManagePersonsPermissionCheckerTask.cs
